/*
 * Copyright (C) 2017--2019, 微笑的丁总 All rights reserved
 * Author: DingJie
 * FileName: OSSUtils
 * Date: 2019/4/25 10:59 PM
 * Description: 阿里云OSS对象存储
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号             描述
 */
package com.dimple.common.utils.file.aliyun;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.dimple.common.utils.DateUtils;
import com.dimple.common.utils.Face2ObjectUtils;
import com.dimple.common.utils.file.FileUploadUtils;
import com.dimple.framework.config.AliOSSConfig;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

/**
 * 〈一句话功能简述〉<br> 阿里云OSS对象存储
 *
 * @author dogjay
 * @create 2019/4/25
 * @since 1.0.0
 */
@Component
@Slf4j
public class OSSUtils {

    @Autowired
    AliOSSConfig aliOSSConfig;

    /**
     * 获取阿里云OSS客户端对象
     */
    public OSSClient getOSSClient() {
        return new OSSClient(aliOSSConfig.getEndpoint(), aliOSSConfig.getAccessKeyId(), aliOSSConfig.getAccessKeySecret());
    }

    /**
     * 新建Bucket  --Bucket权限:私有
     *
     * @param bucketName bucket名称
     * @return true 新建Bucket成功
     */
    public boolean createBucket(OSSClient client, String bucketName) {
        Bucket bucket = client.createBucket(bucketName);
        return bucketName.equals(bucket.getName());
    }

    /**
     * 删除Bucket
     */
    public void deleteBucket(OSSClient client, String bucketName) {
        client.deleteBucket(bucketName);
    }

    /**
     * 向阿里云的OSS存储中存储文件  --file也可以用InputStream替代
     *
     * @param client     OSS客户端
     * @param file       上传文件
     * @param bucketName bucket名称
     * @param diskName   上传文件的目录  --bucket下文件的路径
     * @return String 唯一MD5数字签名
     */
    public String uploadObject2OSS(OSSClient client, File file, String bucketName, String diskName) {
        String resultStr = null;
        try {
            InputStream is = new FileInputStream(file);
            String fileName = file.getName();
            Long fileSize = file.length();
            //创建上传Object的Metadata  
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(is.available());
            metadata.setCacheControl("no-cache");
            metadata.setHeader("Pragma", "no-cache");
            metadata.setContentEncoding("utf-8");
            metadata.setContentType(getContentType(fileName));
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            //上传文件   
            PutObjectResult putResult = client.putObject(bucketName, diskName + fileName, is, metadata);
            //解析结果  
            resultStr = putResult.getETag();
        } catch (Exception e) {
            resultStr = "网络异常!";
        }
        return resultStr;
    }

    /**
     * 根据key获取OSS服务器上的文件输入流
     *
     * @param client     OSS客户端
     * @param bucketName bucket名称
     * @param diskName   文件路径
     * @param key        Bucket下的文件的路径名+文件名
     */
    public InputStream getOSS2InputStream(OSSClient client, String bucketName, String diskName, String key) {
        OSSObject ossObj = client.getObject(bucketName, diskName + key);
        return ossObj.getObjectContent();
    }

    /**
     * 根据key删除OSS服务器上的文件
     *
     * @param client     OSS客户端
     * @param bucketName bucket名称
     * @param diskName   文件路径
     * @param key        Bucket下的文件的路径名+文件名
     */
    public static void deleteFile(OSSClient client, String bucketName, String diskName, String key) {
        client.deleteObject(bucketName, diskName + key);
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public String getContentType(String fileName) {
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if ("bmp".equalsIgnoreCase(fileExtension)) {
            return "image/bmp";
        }
        if ("gif".equalsIgnoreCase(fileExtension)) {
            return "image/gif";
        }
        if ("jpeg".equalsIgnoreCase(fileExtension) || "jpg".equalsIgnoreCase(fileExtension) || "png".equalsIgnoreCase(fileExtension)) {
            return "image/jpeg";
        }
        if ("html".equalsIgnoreCase(fileExtension)) {
            return "text/html";
        }
        if ("txt".equalsIgnoreCase(fileExtension)) {
            return "text/plain";
        }
        if ("vsd".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.visio";
        }
        if ("ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if ("doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
            return "application/msword";
        }
        if ("xml".equalsIgnoreCase(fileExtension)) {
            return "text/xml";
        }
        return "text/html";
    }

    public String uploadImgToAliOSS(MultipartFile file) {
        String result;
        //1.校验文件大小
        FileUploadUtils.assertAllowed(file);
        String imgPath = "";
        String originalFileName = file.getOriginalFilename();
        //编码文件名
        String randomName = FileUploadUtils.encodingFilename(originalFileName);
        Configuration configuration = new Configuration();
        UploadManager uploadManager = new UploadManager(configuration);
//      创建授权
        OSSClient ossClient = getOSSClient();
        File originalFile = new File(file.getName());
        try {
            result = uploadObject2OSS(ossClient, originalFile, aliOSSConfig.getBucketName(), Face2ObjectUtils.getUploadFilePath());
        } catch (Exception e) {
            result = e.getMessage();
        }
        return result;
    }

    /**
     * @param fileName
     * @throws IOException
     */
    public Map<String, String> uploadFileToOSS(String fileName) throws IOException {

        Map<String, String> resultMap = new HashMap<String, String>();
        OSSClient ossClient = new OSSClient(aliOSSConfig.getEndpoint(), aliOSSConfig.getAccessKeyId(), aliOSSConfig.getAccessKeySecret());
        String filePath = "attachment/" +Face2ObjectUtils.generdateFilePath() +UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
        try {
            UploadFileRequest uploadFileRequest = new UploadFileRequest(aliOSSConfig.getBucketName(), filePath);
            // 待上传的本地文件
            uploadFileRequest.setUploadFile(fileName);
            // 设置并发下载数，默认1
            uploadFileRequest.setTaskNum(5);
            // 设置分片大小，默认100KB
            uploadFileRequest.setPartSize(1024 * 1024 * 1);
            // 开启断点续传，默认关闭
            uploadFileRequest.setEnableCheckpoint(true);

            UploadFileResult uploadResult = ossClient.uploadFile(uploadFileRequest);

            CompleteMultipartUploadResult multipartUploadResult = uploadResult.getMultipartUploadResult();
            resultMap.put("success", "true");
            resultMap.put("msg", "文件上传成功！");
            resultMap.put("filePath", "https://" + aliOSSConfig.getBucketName() + "." + aliOSSConfig.getEndpoint() + "/"+filePath);
//            return filePath;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message: " + oe.getErrorCode());
            System.out.println("Error Code:       " + oe.getErrorCode() + "\tRequest ID:      " + oe.getRequestId());
            System.out.println("Host ID:           " + oe.getHostId());
            resultMap.put("success", "false");
            resultMap.put("msg", oe.getMessage());
            resultMap.put("filePath", null);
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ce.getMessage());
            resultMap.put("success", "false");
            resultMap.put("msg", ce.getMessage());
            resultMap.put("filePath", null);
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            ossClient.shutdown();
            System.out.println(resultMap.get("filePath"));
            return resultMap;
        }
    }


    /**
     * @Author DogJay
     * @Describe 在OSS对象存储的Bucket中创建文件夹
     */
    public void createFolderOSS() {

        OSSClient client = getOSSClient();

        try {
            /*
             * Create an empty folder without request body, note that the key must be
             * suffixed with a slash
             */
            String prefix = "upload/" + Face2ObjectUtils.getUploadFilePath();
            client.putObject(aliOSSConfig.getBucketName(), prefix, new ByteArrayInputStream(new byte[0]));

            /*
             * Verify whether the size of the empty folder is zero
             */
            OSSObject object = client.getObject(aliOSSConfig.getBucketName(), prefix);
            object.getObjectContent().close();

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message: " + oe.getErrorCode());
            System.out.println("Error Code:       " + oe.getErrorCode());
            System.out.println("Request ID:      " + oe.getRequestId() + "\tHost ID:           " + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ce.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /*
             * Do not forget to shut down the client finally to release all allocated resources.
             */
            client.shutdown();
        }
    }


    public void deleteFileOSS(List<String> fileName) {
        /*
         * Constructs a client instance with your account for accessing OSS
         */
        OSSClient client = getOSSClient();

        try {

            DeleteObjectsResult deleteObjectsResult = client.deleteObjects(
                    new DeleteObjectsRequest(aliOSSConfig.getBucketName()).withKeys(fileName));

        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message: " + oe.getErrorCode());
            System.out.println("Error Code:       " + oe.getErrorCode());
            System.out.println("Request ID:      " + oe.getRequestId());
            System.out.println("Host ID:           " + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ce.getMessage());
        } finally {
            client.shutdown();
        }
    }
}
